Array.prototype.filter = function(callback) {     
        var rs = [];         
        for ( var i = 0, length = this.length; i < length; i++ ) {     
            if (callback(this[i], i)) {     
                rs.push(this[i]);     
            }     
        }     
        return rs;     
    };
    
if (!String.prototype.startsWith) {
	String.prototype.startsWith = function(searchString, position){
		position = position || 0;
		return this.substr(position, searchString.length) === searchString;
	};
}

function doGetAsyncJson(url, callbackFunc, errFunc) {
	return jQuery.ajax({
		url: encodeURI(url),
		async: true,
		cache: false,
		type: "GET",
		dataType: "json",
		success: function(_data) {
			if (typeof(callbackFunc) == "function") {
				callbackFunc(_data)
			}
		},
		complete: fm_checkSession,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	})
}
function doPostAsyncJson(url, inputData, callbackFunc, errFunc) {
	return jQuery.ajax({
		url: encodeURI(url),
		async: true,
		cache: false,
		type: "POST",
		data: inputData,
		dataType: "json",
		success: function(_data) {
			if (typeof(callbackFunc) == "function") {
				callbackFunc(_data)
			}
		},
		complete: fm_checkSession,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	})
}
function doGetSyncJson(url, inputData, errFunc) {
	var rtndata = null;
	var args = {
		url: encodeURI(url),
		async: false,
		cache: false,
		type: "GET",
		dataType: "json",
		success: function(data) {
			rtndata = data
		},
		complete: fm_checkSession,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	};
	inputData && (args.data = inputData);
	jQuery.ajax(args);
	return rtndata
}
function doPostSyncJson(url, inputData, errFunc) {
	var rtndata = null;
	$.ajax({
		url: encodeURI(url),
		async: false,
		cache: false,
		type: "POST",
		data: inputData,
		dataType: "json",
		success: function(data) {
			rtndata = data
		},
		complete: fm_checkSession,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	});
	return rtndata
}
function doDeleteSyncJson(url, errFunc) {
	var rtndata = null;
	$.ajax({
		contentType: 'application/x-www-form-urlencoded',
		url: encodeURI(url),
		async: false,
		cache: false,
		type: "DELETE",
		dataType: "json",
		success: function(data) {
			rtndata = data
		},
		complete: fm_checkSession,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	});
	return rtndata
}
function doDeleteAsyncJson(url, callbackFunc, errFunc) {
	return $.ajax({
		contentType: 'application/x-www-form-urlencoded',
		url: encodeURI(url),
		async: false,
		cache: false,
		type: "DELETE",
		dataType: "json",
		success: callbackFunc,
		complete: fm_checkSession,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	});
}

//cross domain
function doGetAsyncJsonp(url, callback, errFunc) {
	url = url.replace(/jsoncallback=\?/g,'test=test');
	if(!document.all)console.log(url);
	var args = {
		url: url,
		async: true,
		cache: false,
		type: "GET",
		dataType: "json",
		success: callback,
		//complete: fm_checkSessionJsonp,
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			console.error("Error: accessing "+url+" <br/>[" + textstate + "]: " + errthr);
			msgErr("Error: accessing "+url+" [" + textstate + "]: " + errthr)
		}
	};
	return jQuery.ajax(args);
}

function fm_checkSession(req, txt) {
	if (req.readyState == 4 && req.getResponseHeader('Content-Type') && req.getResponseHeader('Content-Type').indexOf('html') != -1 && req.responseText && req.responseText.indexOf("META_DESC_LOGIN") != -1) {
		if(window.parent) {
			window.parent.location.href = "/";
		} else {
			location.href = "/";
		}
	}
}

function alertErr(title, errMsg) {
	dhtmlx.alert({
		type: "alert-error",
		title: title,
		text: errMsg
	})
}
function alertWarn(title, warnMsg) {
	dhtmlx.alert({
		type: "alert-warning",
		title: title,
		text: warnMsg
	})
}
function alertInfo(title, infoMsg) {
	dhtmlx.alert({
		type: "alert",
		title: title,
		text: infoMsg
	})
}
function msg(msg) {
	dhtmlx.message({
		"text": msg,
		"expire": 8000
	})
}
function msgErr(msg) {
	dhtmlx.message({
		"type": "error",
		"text": msg,
		"expire": -1
	})
}
function confirmWarning(title, text, ok, cancel, callback){
	dhtmlx.message({
        "type": "confirm-warning",
        "title" : title,
		"text": text,
		"ok" : ok,
		"cancel" : cancel,
		"callback" : function(y) {if (y) {callback();}}
	});
}
function openWindowByUrl(_id, _url) {
	var a1new = document.createElement("a");
	a1new.setAttribute("href", _url);
	a1new.setAttribute("target", "_blank");
	a1new.setAttribute("id", "openwin_" + _id);
	document.body.appendChild(a1new);
	a1new.click()
}
function waitstart(msg) {
	$(".waitMsg").html((msg || "") + fmd_i18n_msg_wait);
	$(".wait").show()
}
function waitend() {
	$(".wait").hide();
	$(".waitMsg").html('')
}
function changeicosize(_img, enlarge) {
	if (enlarge) {
		_img.width = 22;
		_img.height = 22
	} else {
		_img.width = 18;
		_img.height = 18
	}
}
function getMousePos(event) {
	var e = event || window.event;
	var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
	var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
	var x = e.pageX || e.clientX + scrollX;
	var y = e.pageY || e.clientY + scrollY;
	return {
		'x': x,
		'y': y
	}
}
function loadModule(lang, modulePath, module, deployVersion, callback) {
	loadJsFile(modulePath + '/' + module + '/i18n_' + lang + '.js?'+deployVersion);
	loadJsFile(modulePath + '/' + module + '/prop.js?'+deployVersion)
	if (typeof(callback)=='function') {
		callback(module);
	}
}
function loadModuleAsync(lang, modulePath, module) {
	return loadJsFile(modulePath + '/' + module + '/i18n_' + lang + '.js', true).then(loadJsFile(modulePath + '/' + module + '/prop.js', true));
}
function loadJsFile(filename, async) {
	return jQuery.ajax({
		url: filename,
		async: !! async,
		cache: true,
		type: "GET",
		dataType: "script",
		error: (typeof(errFunc) == "function") ? errFunc : function(xhr, textstate, errthr) {
			msgErr("Error: [" + textstate + "]: " + errthr)
		}
	})
}
function loadCssFile(filename, filetype) {
	var fileref = document.createElement('link');
	fileref.setAttribute("rel", "stylesheet");
	fileref.setAttribute("type", "text/css");
	fileref.setAttribute("href", filename);
	document.getElementsByTagName("head")[0].appendChild(fileref)
}

function stopEvent(e){
	if (e && e.stopPropagation!=undefined) {
		e.stopPropagation();
	} else if (window.event){
		window.event.cancelBubble = true;
	}
	return false;
}

function closeWin() {
	if ( window.opener && typeof (window.opener.funcRefreshOnChildWinClose) == "function" ) {
		try {
			window.opener.funcRefreshOnChildWinClose();
		} catch(e){console.log('error calling window.opener.funcRefreshOnChildWinClose.'+e)}
	}
	if (window.opener) {
		if (navigator.appName == 'Microsoft Internet Explorer') {
			window.opener = 'whatever';
			window.open('', '_parent', '');
			window.close()
		} else {
			window.open('', '_self', '');
			window.close()
		}
	} else {
		if (navigator.appName == 'Microsoft Internet Explorer') {
			window.opener = null;
			window.open('', '_self', '');
			window.close()
		} else {
			//window.location.href = "about:blank";
			window.opener = null;
			window.open('','_self','');
	        window.close();
	        setTimeout(function(){window.location.href="about:blank";},100);
		}
	}
}

var MyUtilJs = {};

MyUtilJs.getJsonKeyLength = function(obj) {
	var count = 0;
	if ('object'==typeof(obj) && obj && obj.length==undefined) {
		for (var i in obj) {
			count ++;
		}
	}
	return count;
};

MyUtilJs.isEmpty = function(obj) {
	if (!obj) return true;
	for (var i in obj) {
		return false;
	}
	return true;
};

MyUtilJs.copyObj = function(obj) {
	if (!obj) return null;
	if (typeof(obj) != 'object') return obj;
	var newobj = obj instanceof Array ? [] : {};
	for (var i in obj) {
		if (typeof(obj[i]) == 'object') newobj[i] = MyUtilJs.copyObj(obj[i]);
		else newobj[i] = obj[i];
	}
	return newobj;
};

//check equal
MyUtilJs.isEqual = function(a, b) {
	if (!a && !b) {
		return true;
	} else if ((a && !b) || (!a && b)) {
		return false;
	}
	if (typeof(a)!='object' && typeof(b)!='object') {
		return a === b;
	}
    // Of course, we can do it use for in 
    // Create arrays of property names
    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);
    // If number of properties is different,
    // objects are not equivalent
    if (aProps.length != bProps.length) {
        return false;
    }
    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];
        // If values of same property are not equal,
        // objects are not equivalent
        if (a[propName] !== b[propName]) {
            return false;
        }
    }
    // If we made it this far, objects
    // are considered equivalent
    return true;
}

var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function base64encode(str) {
    var out, i, len;
    var c1, c2, c3;

    len = str.length;
    i = 0;
    out = "";
    while(i < len) {
        c1 = str.charCodeAt(i++) & 0xff;
        if(i == len)
        {
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt((c1 & 0x3) << 4);
            out += "==";
            break;
        }
        c2 = str.charCodeAt(i++);
        if(i == len)
        {
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
            out += base64EncodeChars.charAt((c2 & 0xF) << 2);
            out += "=";
            break;
        }
        c3 = str.charCodeAt(i++);
        out += base64EncodeChars.charAt(c1 >> 2);
        out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
        out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
        out += base64EncodeChars.charAt(c3 & 0x3F);
    }
    return out;
}

//兼容浏览器console对象
//创建空console对象，避免JS报错  
if(!window.console)  {
	var c = {};
	var funcs = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml',  
	             'error', 'exception', 'group', 'groupCollapsed', 'groupEnd',  
	             'info', 'log', 'markTimeline', 'profile', 'profileEnd',  
	             'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];  
	for(var i=0,l=funcs.length;i<l;i++) {  
	    var func = funcs[i];  
	    if(!c[func])
	        c[func] = function(){};  
	}
	window.console = c;
}


